module o_crc8 
#(
    parameter OUT_REG = 1'B1
)
(
    input wire [7:0] data_in,
    input wire data_in_en,
    input wire clk,
    input wire resetn,
    input wire clr,
    output wire [7:0] crc_out,
    output wire crc_done
);

    reg [7:0] c;
    reg [7:0] temp;
    reg [7:0] d;
    reg data_in_en_dly2,data_in_en_dly1;
    /*
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            c <= 8'b0;
            temp <= 8'b0;
            d <= 8'b0;
        end else begin
            d <= data_in;

            temp[0] = d[7] ^ d[6] ^ d[0] ^ c[0] ^ c[6] ^ c[7];
            temp[1] = d[6] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[6];
            temp[2] = d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[6];
            temp[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[3] ^ c[7];
            temp[4] = d[4] ^ d[3] ^ d[2] ^ c[2] ^ c[3] ^ c[4];
            temp[5] = d[5] ^ d[4] ^ d[3] ^ c[3] ^ c[4] ^ c[5];
            temp[6] = d[6] ^ d[5] ^ d[4] ^ c[4] ^ c[5] ^ c[6];
            temp[7] = d[7] ^ d[6] ^ d[5] ^ c[5] ^ c[6] ^ c[7];
            
            c <= temp;
        end
    end

    assign crc_out = c;

    */

    always @(posedge clk or negedge resetn) begin
        if (!resetn) begin 
            d <= 8'b0;
        end 
        else if(clr) begin
            d <= 8'b0;
        end
        else if (data_in_en) begin
            d <= data_in; 
        end
    end

    always @(*) begin
        if(!resetn) begin 
            temp = 8'b0;
        end 
        else begin 
            temp[0] = d[7] ^ d[6] ^ d[0] ^ c[0] ^ c[6] ^ c[7];
            temp[1] = d[6] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[6];
            temp[2] = d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[6];
            temp[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[3] ^ c[7];
            temp[4] = d[4] ^ d[3] ^ d[2] ^ c[2] ^ c[3] ^ c[4];
            temp[5] = d[5] ^ d[4] ^ d[3] ^ c[3] ^ c[4] ^ c[5];
            temp[6] = d[6] ^ d[5] ^ d[4] ^ c[4] ^ c[5] ^ c[6];
            temp[7] = d[7] ^ d[6] ^ d[5] ^ c[5] ^ c[6] ^ c[7];
        end
    end

    always @(posedge clk or negedge resetn) begin
        if (!resetn) begin
            c <= 8'b0; 
        end 
        else if(clr) begin
            c <= 8'b0; 
        end
        else if(crc_done) begin 
            c <= temp;
        end
    end

    //data_in_en
    always @(posedge clk or negedge resetn) begin
        if (!resetn) begin
            data_in_en_dly1 <= 1'b0; 
            data_in_en_dly2 <= 1'b0; 
        end 
        else if(clr) begin
            data_in_en_dly1 <= 1'b0; 
            data_in_en_dly2 <= 1'b0; 
        end
        else begin 
            data_in_en_dly1 <= data_in_en;
            data_in_en_dly2 <= data_in_en_dly1;
        end
    end
    assign crc_out = OUT_REG ? c : temp;
    assign crc_done = OUT_REG ? data_in_en_dly2 : data_in_en_dly1 ;

endmodule
